home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d3 / ted12.arc / TEDNEW.ASM < prev    next >
Assembly Source File  |  1990-07-24  |  52KB  |  1,673 lines

  1.  
  2.         page    53,132
  3.         title    TED: The Tiny EDitor, ver. 1.2
  4. ;
  5. ;======================================================================
  6. ;
  7. ;  TED.ASM -- The Tiny EDitor.
  8. ;  PC Magazine * Tom Kihlken
  9. ;
  10. ;
  11. ;  Revised 11/15/88 version 1.1
  12. ;  ----------------------------
  13. ;
  14. ;
  15. ;  Revised 7/4/90 version 1.2 by Shaw Bridges
  16. ;  ------------------------------------------
  17. ;
  18. ;  F1 Abort warning message conditional on actual modifications
  19. ;    to the file.  See variable "changed".
  20. ;
  21. ;  Screen displays tabs and carriage returns, but these can
  22. ;    easily suppressed.  Search for  ;****disp  and see variables
  23. ;    "tab_disp" and "cr_disp".
  24. ;
  25. ;  UNDO (F2) works on Delete and/or Backspace; it does not
  26. ;    attempt to undo overstrike.
  27. ;
  28. ;======================================================================
  29. ;
  30. ;
  31. CSEG        SEGMENT                ;***********************;
  32.         ASSUME    CS:CSEG,DS:CSEG,ES:CSEG    ;                       ;
  33.         ORG    100H            ;  REMEMBER TO EXE2BIN  ;
  34. START:                        ;                       ;
  35.         JMP    BEGIN            ;***********************;
  36.  
  37.  
  38. ;-----------------------------------------------------------------------
  39. ; Local data area
  40. ;-----------------------------------------------------------------------
  41. TAB        EQU    9
  42. CR        EQU    13
  43. LF        EQU    10
  44.  
  45. COPYRIGHT    DB    CR,LF,LF,"TED 1.2 (c) 1988-90 Ziff Communications Co."
  46.         DB    CR,LF,"PC Magazine ",254," Tom Kihlken",CR,LF,"$"
  47.  
  48. FILE_TOO_BIG    DB    "File too big$"
  49. READ_ERR_MSG    DB    "Read error$"
  50. MEMORY_ERROR    DB    "Not enough memory$"
  51.  
  52. PROMPT_STRING    DB    "1ABORT",0,"2UNDO",0,"3PRINT",0
  53.         DB    "4MARK",0,"5CUT",0,"6PASTE",0,"7EXIT",0
  54.         DB    "8DEL EOL",0,"9DEL L",0,"10UDEL L",0,0
  55. PROMPT_LENGTH    =    $ - OFFSET PROMPT_STRING
  56.  
  57. VERIFY_MSG    DB    "Lose Changes (Y/N)?",0
  58. SAVE_MSG    DB    "Save as: ",0
  59. DOT_$$$        DB    ".$$$",0
  60. DOT_BAK        DB    ".BAK",0
  61.  
  62. ;****disp    Symbols for displaying tabs and carriage returns
  63. tab_disp    db    10H            ;Replace with " " to suppress
  64.                         ; on screen tab display
  65. cr_disp        db    14H            ;Search for ;****disp to find
  66.                         ; instructions for suppressing
  67.                         ; on screen CR display.
  68. ;****disp
  69.  
  70. DIRTY_BITS    DB    1
  71. changed        db    0            ;File modified: 0 = no, 1 = yes
  72. NORMAL        DB    07H
  73. INVERSE        DB    70H
  74. LEFT_MARGIN    DB    0
  75. MARGIN_COUNT    DB    0
  76. INSERT_MODE    DB    -1
  77. MARK_MODE    DB    0
  78. ROWS        DB    23
  79. SAVE_COLUMN    DB    0
  80. SAVE_ROW    DB    0
  81. LINE_FLAG    DB    0
  82. save_flag    db    ?            ;0 Save on delete at end of stack
  83.                         ;1 Save on Bksp at front of stack
  84.                         ;2 Save LF after CR on bksp delete
  85. EVEN
  86. NAME_POINTER    DW    81H
  87. NAME_END    DW    81H
  88. STATUS_REG    DW    ?
  89. VIDEO_SEG    DW    0B000H
  90. LINE_LENGTH    DW    0
  91. UNDO_LENGTH    DW    0
  92. left_count    dw    0            ;no. of bksp. deletes for undo
  93. CUR_POSN    DW    0
  94. MARK_START    DW    0FFFFH
  95. MARK_END    DW    0
  96. MARK_HOME    DW    0
  97. TOP_OF_SCREEN    DW    0
  98. CURSOR        DW    0
  99. LAST_CHAR    DW    0
  100. COLUMNSB    LABEL    BYTE
  101. COLUMNS        DW    ?
  102. PASTE_SEG    DW    ?
  103. PASTE_SIZE    DW    0
  104. PAGE_PROC    DW    ?
  105. OLDINT24    DD    ?
  106. DISPATCH_TABLE    DW    OFFSET ABORT   ,OFFSET UNDO   ,OFFSET PRINT
  107.         DW    OFFSET MARK    ,OFFSET CUT    ,OFFSET PASTE
  108.         DW    OFFSET EXIT    ,OFFSET DEL_EOL,OFFSET DEL_L
  109.         DW    OFFSET UDEL_L  ,OFFSET BAD_KEY,OFFSET BAD_KEY
  110.         DW    OFFSET HOME    ,OFFSET UP     ,OFFSET PGUP
  111.         DW    OFFSET BAD_KEY ,OFFSET LEFT   ,OFFSET BAD_KEY
  112.         DW    OFFSET RIGHT   ,OFFSET BAD_KEY,OFFSET ENDD
  113.         DW    OFFSET DOWN    ,OFFSET PGDN   ,OFFSET INSERT
  114.         DW    OFFSET DEL_CHAR
  115.  
  116. ; The following machine instruction removes the desnow delay.  It is
  117. ; inserted into the code for EGA, VGA, and MONO displays.
  118.  
  119. NO_DESNOW    =    0EBH + (OFFSET WRITE_IT - OFFSET HWAIT - 2) * 256
  120.  
  121.  
  122.  
  123.         ;*********************;
  124.         ;                     ;
  125.         ;  M A I N   C O D E  ;
  126.         ;                     ;
  127.         ;*********************;
  128.  
  129.  
  130. ;-----------------------------------------------------------------------
  131. ; We start by initialize the display, then allocate memory for the file
  132. ; and paste segments.  Parse the command line for a filename, if one was
  133. ; input, read in the file.  Finally set the INT 23 and 24 vectors.
  134. ;-----------------------------------------------------------------------
  135. BEGIN:
  136.         XOR    AX,AX
  137.         MOV    DS,AX            ;Get a zero into DS
  138.         ASSUME    DS:NOTHING
  139.         MOV    AH,12H
  140.         MOV    BL,10H            ;Get EGA info
  141.         INT    10H
  142.         CMP    BL,10H            ;Did BL change?
  143.         JE    NOT_EGA            ;If not, no EGA in system
  144.         TEST    BYTE PTR DS:[0487H],8    ;Is EGA active?
  145.         JNZ    NOT_EGA
  146.         MOV    WORD PTR CS:HWAIT,NO_DESNOW    ;Get rid of desnow
  147.         MOV    AX,DS:[0484H]        ;Get number of rows
  148.         DEC    AL            ;Last row is for prompt line
  149.         MOV    CS:[ROWS],AL        ;Save the number of rows
  150. NOT_EGA:
  151.         MOV    AX,DS:[044AH]        ;Get number of columns
  152.         MOV    CS:COLUMNS,AX        ;and store it
  153.         MOV    AX,DS:[0463H]        ;Address of display card
  154.         ADD    AX,6            ;Add six to get status port
  155.         PUSH    CS
  156.         POP    DS
  157.         ASSUME    DS:CSEG
  158.         MOV    STATUS_REG,AX
  159.         CMP    AX,3BAH            ;Is this a MONO display?
  160.         JNE    COLOR            ;If not, must be a CGA
  161.         MOV    WORD PTR HWAIT,NO_DESNOW    ;Get rid of desnow
  162.         JMP    SHORT MOVE_STACK
  163. COLOR:
  164.         MOV    VIDEO_SEG,0B800H    ;Segment for color card
  165.         XOR    BH,BH            ;Use page zero
  166.         MOV    AH,8            ;Get current attribute
  167.         INT    10H
  168.         MOV    NORMAL,AH        ;Save the normal attribute
  169.         XOR    AH,1110111B        ;Flip the color bits
  170.         MOV    INVERSE,AH
  171. MOVE_STACK:
  172.         MOV    BX,OFFSET NEW_STACK
  173.         MOV    SP,BX            ;Move the stack downward
  174.         ADD    BX,15
  175.         MOV    CL,4            ;Convert program size to
  176.         SHR    BX,CL            ; paragraphs
  177.         MOV    AH,4AH            ;Deallocate unused memory
  178.         INT    21H
  179.         MOV    BX,1000H        ;Request 64K for file segment
  180.         MOV    AH,48H
  181.         INT    21H
  182.         MOV    ES,AX
  183.         ASSUME    ES:FILE_SEG
  184.         MOV    AH,48H
  185.         INT    21H            ;Request 64K for paste buffer
  186.         JNC    GOT_ENOUGH        ;If enough memory, continue
  187.         MOV    DX,OFFSET MEMORY_ERROR
  188. ERR_EXIT:
  189.         PUSH    CS
  190.         POP    DS
  191.         MOV    AH,9            ;Write the error message
  192.         INT    21H            ;DOS display service
  193.         JMP    EXIT_TO_DOS        ;Exit this program
  194. GOT_ENOUGH:
  195.         MOV    PASTE_SEG,AX        ;Use this for the paste buffer
  196.         MOV    SI,80H            ;Point to parameters
  197.         MOV    CL,[SI]            ;Get number of characters
  198.         XOR    CH,CH            ;Make it a word
  199.         INC    SI            ;Point to first character
  200.         PUSH    SI
  201.         ADD    SI,CX            ;Point to last character
  202.         MOV    BYTE PTR [SI],0        ;Make it an ASCII string
  203.         MOV    NAME_END,SI        ;Save pointer to last character
  204.         POP    SI            ;Get back pointer to filename
  205.         CLD
  206.         JCXZ    NO_FILENAME        ;If no params, just exit
  207. DEL_SPACES:    LODSB                ;Get character into AL
  208.         CMP    AL," "            ;Is it a space?
  209.         JNE    FOUND_LETTER
  210.         LOOP    DEL_SPACES
  211. FOUND_LETTER:
  212.         DEC    SI            ;Backup pointer to first letter
  213.         MOV    NAME_POINTER,SI        ;Save pointer to filename
  214.         MOV    DX,SI
  215.         MOV    AX,3D00H        ;Setup to open file
  216.         INT    21H
  217.         JC    NO_FILENAME        ;If we can't open, must be new file
  218.         PUSH    ES
  219.         POP    DS            ;DS has file segment also
  220.         ASSUME    DS:FILE_SEG
  221.         MOV    BX,AX            ;Get the handle into BX
  222.         XOR    DX,DX            ;Point to file buffer
  223.         MOV    AH,3FH            ;Read service
  224.         MOV    CX,0FFFEH        ;Read almost 64K bytes
  225.         INT    21H
  226.         MOV    DI,AX            ;Number of bytes read in
  227.         JNC    LOOK_FOR_EOF        ;If no error, take jump
  228.         MOV    DX,OFFSET READ_ERR_MSG
  229.         JMP    SHORT ERR_EXIT
  230. LOOK_FOR_EOF:
  231.         CMP    BYTE PTR [DI-1],1AH    ;Was last char an EOF mark?
  232.         JNE    NO_EOF            ;If not, everything is OK
  233.         DEC    DI            ;Backup to last character
  234. NO_EOF:
  235.         MOV    LAST_CHAR,DI        ;Save the file size
  236.         CMP    CX,AX            ;Did the buffer fill?
  237.         MOV    DX,OFFSET FILE_TOO_BIG
  238.         JE    ERR_EXIT        ;If yes, it is too big
  239.         MOV    AH,3EH
  240.         INT    21H            ;Close the file
  241. NO_FILENAME:
  242.         PUSH    ES
  243.         PUSH    ES            ;Save file segment
  244.         MOV    AX,3524H        ;Get INT 24 vector
  245.         INT    21H
  246.         MOV    WORD PTR OLDINT24,BX    ;Store the offset
  247.         MOV    WORD PTR OLDINT24+2,ES    ;And the segment
  248.  
  249.         PUSH    CS
  250.         POP    DS
  251.         MOV    DX,OFFSET NEWINT24    ;Point to new vector
  252.         MOV    AX,2524H        ;Now change INT 24 vector
  253.         INT    21H
  254.  
  255.         MOV    DX,OFFSET NEWINT23
  256.         MOV    AX,2523H        ;Set the INT 23 vector also
  257.         INT    21H
  258.  
  259.         POP    ES            ;Get back file segment
  260.         POP    DS
  261.         CALL    REDO_PROMPT        ;Draw the prompt line
  262.  
  263. ;-----------------------------------------------------------------------
  264. ; Here's the main loop.  It updates the screen, then reads a keystroke.
  265. ;-----------------------------------------------------------------------
  266. READ_A_KEY:
  267.         CMP    MARK_MODE,0        ;Is the mark state on?
  268.         JE    MARK_OFF        ;If not, skip this
  269.         OR    DIRTY_BITS,4        ;Refresh the current row
  270.         MOV    DX,CUR_POSN
  271.         CMP    SAVE_ROW,DH        ;Are we on the save row?
  272.         JE    SAME_ROW        ;If yes, then redo the row only
  273.         MOV    DIRTY_BITS,1        ;Refresh the whole screen
  274. SAME_ROW:
  275.         MOV    AX,CURSOR        ;Get cursor location
  276.         MOV    BX,MARK_HOME        ;Get the anchor mark position
  277.         CMP    AX,BX            ;Moving backward in file?
  278.         JAE    S1
  279.         MOV    MARK_START,AX        ;Switch start and end position
  280.         MOV    MARK_END,BX
  281.         JMP    SHORT MARK_OFF
  282. S1:
  283.         MOV    MARK_END,AX        ;Store start and end marks
  284.         MOV    MARK_START,BX
  285. MARK_OFF:
  286.         MOV    DX,CUR_POSN
  287.         MOV    SAVE_ROW,DH
  288.         CALL    SET_CURSOR        ;Position the cursor
  289.         TEST    DIRTY_BITS,1        ;Look at screen dirty bit
  290.         JZ    SCREEN_OK        ;If zero, screen is OK
  291.  
  292.         MOV    AH,1            ;Get keyboard status
  293.         INT    16H            ;Any keys ready?
  294.         JNZ    CURRENT_OK        ;If yes, skip the update
  295.         CALL    DISPLAY_SCREEN        ;Redraw the screen
  296.         MOV    DIRTY_BITS,0        ;Mark screen as OK
  297. SCREEN_OK:
  298.         TEST    DIRTY_BITS,4        ;Is the current line dirty?
  299.         JZ    CURRENT_OK        ;If not, take jump
  300.         CALL    DISPLAY_CURRENT        ;Redraw the current line
  301.         MOV    DIRTY_BITS,0        ;Mark screen as OK
  302. CURRENT_OK:
  303.         XOR    AH,AH            ;Read the next key
  304.         INT    16H
  305.         OR    AL,AL            ;Is this an extended code?
  306.         JZ    EXTENDED_CODE
  307.         CMP    AH,0EH            ;Was it the backspace key?
  308.         JE    BACK_SPACE
  309.         CALL    INSERT_KEY        ;Put this character in the file
  310.         JMP    READ_A_KEY        ;Get another key
  311. BACK_SPACE:
  312.         CMP    CURSOR,0        ;At start of file?
  313.         JE    BAD_KEY            ;If at start, can't backspace
  314.         call    left_del        ;Move left one space
  315.         mov    save_flag,1        ;Set switch to show bksp
  316.         call    del_ch2            ;And delete the character
  317.         JMP    READ_A_KEY
  318. EXTENDED_CODE:
  319.         CMP    AH,84H            ;Is it control PgUp?
  320.         JNE    NOT_TOP
  321.         CALL    TOP
  322.         JMP    READ_A_KEY
  323. NOT_TOP:
  324.         CMP    AH,76H            ;Is it control PgDn?
  325.         JNE    NOT_BOTTOM
  326.         CALL    BOTTOM
  327. BAD_KEY:
  328.         JMP    READ_A_KEY
  329. NOT_BOTTOM:
  330.         CMP    AH,73H            ;Is it control left arrow?
  331.         JE    SH_LEFT
  332.         CMP    AH,74H            ;Is it control right arrow?
  333.         JE    SH_RIGHT
  334.         CMP    AH,53H            ;Skip high numbered keys
  335.         JA    BAD_KEY
  336.         XCHG    AH,AL
  337.         SUB    AL,3BH            ;Also skip low numbered keys
  338.         JC    BAD_KEY
  339.         SHL    AX,1            ;Make the code an offset
  340.         MOV    BX,AX            ;Put offset in BX
  341.         CALL    CS:DISPATCH_TABLE[BX]    ;Call the key procedure
  342.         JMP    READ_A_KEY        ;Then read another key
  343.  
  344. ;-----------------------------------------------------------------------
  345. ; These two routines shift the display right or left to allow editing
  346. ; files which contain lines longer than 80 columns.
  347. ;-----------------------------------------------------------------------
  348. SH_RIGHT    PROC    NEAR
  349.         CMP    LEFT_MARGIN,255 - 8    ;Past max allowable margin?
  350.         JAE    NO_SHIFT        ;Then can't move any more
  351.         ADD    LEFT_MARGIN,8        ;This moves the margin over
  352. SH_RETURN:
  353.         CALL    CURSOR_COL        ;Compute column for cursor
  354.         MOV    DX,CUR_POSN
  355.         MOV    SAVE_COLUMN,DL        ;Save the current column
  356.         MOV    DIRTY_BITS,1        ;Redraw the screen
  357. NO_SHIFT:
  358.         JMP    READ_A_KEY
  359. SH_RIGHT    ENDP
  360.  
  361. SH_LEFT        PROC    NEAR
  362.         CMP    LEFT_MARGIN,0        ;At start of line already?
  363.         JE    NO_SHIFT        ;If yes, then don't shift
  364.         SUB    LEFT_MARGIN,8        ;Move the window over
  365.         JMP    SH_RETURN
  366. SH_LEFT        ENDP
  367.  
  368. ;-----------------------------------------------------------------------
  369. ; This routine adds a character into the file.  In insert mode, remaining
  370. ; characters are pushed forward.  If a CR is inserted, a LF is added also.
  371. ;-----------------------------------------------------------------------
  372. INSERT_KEY    PROC    NEAR
  373.         mov    changed,1        ;Set file modified switch
  374.         mov    undo_length,0        ;Reset length of UNDO buffer.
  375.         MOV    SI,CURSOR        ;Set base registers
  376.         mov    di,si
  377.         CMP    AL,CR            ;Was this a carriage return
  378.         JE    NEW_LINE
  379.         CMP    INSERT_MODE,0        ;In insert mode?
  380.         JNE    INSERT_CHAR
  381.         CMP    BYTE PTR [SI],CR    ;At end of line?
  382.         JE    INSERT_CHAR
  383.         CMP    SI,LAST_CHAR        ;At end of file?
  384.         jne    store_it
  385. INSERT_CHAR:
  386.         PUSH    SI
  387.         PUSH    AX            ;Save the new character
  388.         MOV    AX,1
  389.         CALL    OPEN_SPACE        ;Make room for it
  390.         POP    AX            ;Get back the new character
  391.         POP    DI
  392.         JC    FILE_FULL
  393. store_it:
  394.         STOSB                ;Insert character in file buffer
  395.         OR    DIRTY_BITS,4        ;Current line is dirty
  396.         CALL    right_2            ;Move cursor to next letter
  397. FILE_FULL:
  398.         RET
  399. NEW_LINE:
  400.         PUSH    SI
  401.         MOV    AX,2
  402.         CALL    OPEN_SPACE        ;Make space for CR and LF
  403.         POP    DI            ;Get back old cursor location
  404.         JC    FILE_FULL
  405.         MOV    AX,LF*256+CR
  406.         STOSW                ;Store the CR and LF
  407.         CALL    DISPLAY_BOTTOM        ;Repaint bottom of the screen
  408.         CALL    home_2            ;Cursor to start of line
  409.         jmp    down_2            ;And move down one row
  410. INSERT_KEY    ENDP
  411.  
  412. ;-----------------------------------------------------------------------
  413. ; This moves the cursor to the top of the file.
  414. ;-----------------------------------------------------------------------
  415. TOP        PROC    NEAR
  416.         mov    undo_length,0        ;Reset length of UNDO buffer.
  417.         XOR    AX,AX            ;Get a zero into AX
  418.         MOV    CURSOR,AX        ;Cursor to start of file
  419.         MOV    TOP_OF_SCREEN,AX
  420.         MOV    LEFT_MARGIN,AL        ;Move to far left margin
  421.         MOV    DIRTY_BITS,1        ;Redraw the screen
  422.         MOV    CUR_POSN,AX        ;Home the cursor
  423.         MOV    SAVE_COLUMN,AL        ;Save the cursor column
  424.         RET
  425. TOP        ENDP
  426.  
  427. ;-----------------------------------------------------------------------
  428. ; This moves the cursor to the bottom of the file.
  429. ;-----------------------------------------------------------------------
  430. BOTTOM        PROC    NEAR
  431.         mov    undo_length,0        ;Reset length of UNDO buffer.
  432.         MOV    DH,ROWS            ;Get screen size
  433.         MOV    SI,LAST_CHAR        ;Point to last character
  434.         MOV    LEFT_MARGIN,0        ;Set window to start of line
  435.         CALL    LOCATE            ;Adjust the screen position
  436.         CALL    home_2            ;Move cursor to start of line
  437.         MOV    DIRTY_BITS,1        ;This will redraw the screen
  438.         RET
  439. BOTTOM        ENDP
  440.  
  441. ;-----------------------------------------------------------------------
  442. ; This deletes from the cursor position to the end of line.
  443. ;-----------------------------------------------------------------------
  444. DEL_EOL        PROC    NEAR
  445.         MOV    LINE_FLAG,0
  446.         PUSH    CURSOR            ;Save starting cursor location
  447.         CALL    endd_2            ;Move the the end of line
  448.         POP    SI            ;Get back starting cursor
  449.         MOV    CX,CURSOR        ;Offset of the end of line
  450.         MOV    CURSOR,SI        ;Restore starting cursor
  451.         JMP    SHORT DEL_END        ;Delete characters to end
  452. DEL_EOL        ENDP
  453.  
  454. ;-----------------------------------------------------------------------
  455. ; This deletes a line, placing it in the line buffer.
  456. ;-----------------------------------------------------------------------
  457. DEL_L        PROC    NEAR
  458.         MOV    LINE_FLAG,1
  459.         CALL    FIND_START        ;Find start of this line
  460.         MOV    CURSOR,SI        ;This will be the new cursor
  461.         PUSH    SI            ;Save the cursor position
  462.         CALL    FIND_NEXT        ;Find the next line
  463.         MOV    CX,SI            ;CX will hold line length
  464.         POP    SI            ;Get back new cursor location
  465. DEL_END:
  466.         SUB    CX,SI            ;Number of bytes on line
  467.         OR    CH,CH            ;Is line too long to fit
  468.         JZ    NOT_TOO_LONG
  469.         MOV    CX,100H            ;Only save 256 characters
  470. NOT_TOO_LONG:
  471.         MOV    LINE_LENGTH,CX        ;Store length of deleted line
  472.         JCXZ    NO_DEL_L
  473.         mov    changed,1        ;Set file modified switch
  474.         mov    undo_length,0        ;Reset length of UNDO buffer.
  475.         MOV    DI,OFFSET LINE_BUFFER    ;Buffer for deleted line
  476.  
  477.         PUSH    CX
  478.         PUSH    ES
  479.         PUSH    CS
  480.         POP    ES            ;Line buffer is in CSEG
  481.         REP    MOVSB            ;Put deleted line in buffer
  482.         POP    ES            ;Get back file segment
  483.         POP    AX
  484.  
  485.         MOV    CX,LAST_CHAR        ;Get the file size
  486.         SUB    LAST_CHAR,AX        ;Subtract the deleted line
  487.         MOV    SI,CURSOR        ;Get new cursor location
  488.         MOV    DI,SI
  489.         ADD    SI,AX            ;SI points to end of file
  490.         SUB    CX,SI            ;Length of remaining file
  491.         JCXZ    NO_DEL_L
  492.         REP    MOVSB            ;Shift remainder of file up
  493. NO_DEL_L:
  494.         MOV    DX,CUR_POSN        ;Get cursor row/column
  495.         MOV    SI,CURSOR        ;Get cursor offset
  496.         CALL    LOCATE            ;Adjust the screen position
  497.         MOV    DIRTY_BITS,1        ;Redraw the screen
  498.         RET
  499. DEL_L        ENDP
  500.  
  501. ;-----------------------------------------------------------------------
  502. ; This undeletes a line by copying it from the line buffer into the file.
  503. ;-----------------------------------------------------------------------
  504. UDEL_L        PROC    NEAR
  505.         mov    undo_length,0        ;Reset length of UNDO buffer.
  506.         mov    left_count,0        ; and bksp delete counter
  507.         CMP    LINE_FLAG,0        ;Is this an end of line only?
  508.         JE    UDEL_EOL        ;If yes, don't home the cursor
  509.         CALL    home_2            ;Move cursor to home
  510. UDEL_EOL:
  511.         MOV    AX,LINE_LENGTH        ;Length of deleted line
  512.         MOV    SI,OFFSET LINE_BUFFER
  513.         JMP    INSERT_STRING
  514. UDEL_L        ENDP
  515.  
  516. ;-----------------------------------------------------------------------
  517. ; These routines move the cursor left and right.
  518. ;-----------------------------------------------------------------------
  519. LEFT        PROC    NEAR
  520.         mov    undo_length,0
  521. left_2:
  522.         CMP    CURSOR,0        ;At start of file?
  523.         JZ    LR_NO_CHANGE        ;Then can't move left
  524. left_del:
  525.         MOV    DX,CUR_POSN
  526.         OR    DL,DL            ;At first column?
  527.         JZ    MOVE_UP            ;If yes, then move up one
  528.         DEC    CURSOR            ;Shift the cursor offset
  529. LR_RETURN:
  530.         CALL    CURSOR_COL        ;Compute column for cursor
  531.         MOV    SAVE_COLUMN,DL        ;Save the cursor column
  532. LR_NO_CHANGE:
  533.         RET
  534. MOVE_UP:
  535.         CALL    up_2            ;Move up to previous row
  536.         JMP    SHORT endd_2        ;And move to end of line
  537. LEFT        ENDP
  538.  
  539. RIGHT        PROC    NEAR
  540.         mov    undo_length,0
  541. right_2:
  542.         MOV    SI,CURSOR
  543.         CMP    SI,LAST_CHAR        ;At end of file?
  544.         JE    LR_NO_CHANGE        ;If yes, then can't move
  545.         CMP    BYTE PTR [SI],CR    ;At end of line?
  546.         JE    MOVE_DOWN        ;If yes, then move down
  547.         INC    CURSOR            ;Advance the cursor
  548.         JMP    LR_RETURN
  549. MOVE_DOWN:
  550.         CALL    home_2            ;Move to start of line
  551.         jmp    down_2            ;And move down one row
  552. RIGHT        ENDP
  553.  
  554. ;-----------------------------------------------------------------------
  555. ; This moves the cursor to the start of the current line.
  556. ;-----------------------------------------------------------------------
  557. HOME        PROC    NEAR
  558.         mov    undo_length,0        ;Reset length of UNDO buffer.
  559. home_2:
  560.         CALL    FIND_START        ;Find start of line
  561.         MOV    CURSOR,SI        ;Save the new cursor
  562.         MOV    SAVE_COLUMN,0        ;Save the cursor column
  563.         MOV    BYTE PTR CUR_POSN,0    ;Store column number
  564.         RET
  565. HOME        ENDP
  566.  
  567. ;-----------------------------------------------------------------------
  568. ; This moves the cursor to the end of the current line.
  569. ;-----------------------------------------------------------------------
  570. ENDD        PROC    NEAR
  571.         mov    undo_length,0        ;Reset length of UNDO buffer.
  572. endd_2:
  573.         MOV    SI,CURSOR
  574.         CALL    FIND_EOL        ;Find end of this line
  575.         MOV    CURSOR,SI        ;Store the new cursor
  576.         CALL    CURSOR_COL        ;Compute the correct column
  577.         MOV    SAVE_COLUMN,DL        ;Save the cursor column
  578.         RET
  579. ENDD        ENDP
  580.  
  581. ;-----------------------------------------------------------------------
  582. ; This moves the cursor up one row.  If the cursor is at the first row,
  583. ; the screen is scrolled down.
  584. ;-----------------------------------------------------------------------
  585. UP        PROC    NEAR
  586.         MOV    UNDO_LENGTH,0
  587. up_2:
  588.         MOV    DX,CUR_POSN
  589.         MOV    SI,CURSOR
  590.         OR    DH,DH            ;At top row already?
  591.         JZ    SCREEN_DN        ;If yes, then scroll down
  592.         DEC    DH            ;Move cursor up one row
  593.         CALL    FIND_CR            ;Find the beginning of this row
  594.         MOV    CURSOR,SI
  595.         CALL    FIND_START        ;Find start of this row
  596.         MOV    CURSOR,SI
  597.         CALL    SHIFT_RIGHT        ;Skip over to current column
  598. AT_TOP:
  599.         RET
  600. SCREEN_DN:
  601.         MOV    SI,TOP_OF_SCREEN
  602.         OR    SI,SI            ;At start of file?
  603.         JZ    AT_TOP            ;If at top, then do nothing
  604.         CALL    FIND_PREVIOUS        ;Find the preceeding line
  605.         MOV    TOP_OF_SCREEN,SI    ;Save new top of screen
  606.         MOV    SI,CURSOR
  607.         CALL    FIND_PREVIOUS        ;Find the preceeding line
  608.         MOV    CURSOR,SI        ;This is the new cursor
  609. SHIFT_RET:
  610.         MOV    DIRTY_BITS,1        ;Need to redraw screen
  611.         MOV    SI,CURSOR
  612.         MOV    DX,CUR_POSN
  613.         JMP    SHIFT_RIGHT        ;Move cursor to current column
  614. UP        ENDP
  615.  
  616. ;-----------------------------------------------------------------------
  617. ; This moves the cursor down one row.  When the last row is reached,
  618. ; the screen is shifted up one row.
  619. ;-----------------------------------------------------------------------
  620. DOWN        PROC    NEAR
  621.         MOV    UNDO_LENGTH,0
  622. down_2:
  623.         MOV    DX,CUR_POSN
  624.         CMP    DH,ROWS            ;At bottom row already?
  625.         MOV    SI,CURSOR        ;Get position in file
  626.         JE    SCREEN_UP        ;If at bottom, then scroll up
  627.         CALL    FIND_NEXT        ;Find the start of next line
  628.         JC    DOWN_RET        ;If no more lines, then return
  629.         MOV    CURSOR,SI
  630.         INC    DH            ;Advance cursor to next row
  631.         CALL    SHIFT_RIGHT        ;Move cursor to current column
  632. DOWN_RET:
  633.         RET
  634. SCREEN_UP:
  635.         CMP    SI,LAST_CHAR        ;Get cursor offset
  636.         JE    DOWN_RET
  637.         CALL    FIND_START        ;Find the start of this line
  638.         MOV    CURSOR,SI        ;This is the new cursor
  639.         CALL    FIND_NEXT        ;Find the offset of next line
  640.         JC    SHIFT_RET        ;If no more lines then return
  641.         MOV    CURSOR,SI        ;This is the new cursor
  642.         MOV    SI,TOP_OF_SCREEN    ;Get the start of the top row
  643.         CALL    FIND_NEXT        ;And find the next line
  644.         MOV    TOP_OF_SCREEN,SI    ;Store the new top of screen
  645.         JMP    SHIFT_RET
  646. DOWN        ENDP
  647.  
  648. ;-----------------------------------------------------------------------
  649. ; These two routines move the screen one page at a time by calling the
  650. ; UP and DOWN procedures.
  651. ;-----------------------------------------------------------------------
  652. PGDN        PROC    NEAR
  653.         MOV    PAGE_PROC,OFFSET down_2    ;Set to move down 1 row
  654. PAGE_UP_DN:
  655.         mov    undo_length,0        ;Reset length of UNDO buffer.
  656.         MOV    CL,ROWS            ;Get length of the screen
  657.         SUB    CL,5            ;Don't page a full screen
  658.         XOR    CH,CH            ;Make it a word
  659. PAGE_LOOP:
  660.         PUSH    CX
  661.         CALL    PAGE_PROC        ;Move the cursor down
  662.         POP    CX
  663.         LOOP    PAGE_LOOP        ;Loop for one page length
  664.         RET
  665. PGDN        ENDP
  666.  
  667. PGUP        PROC    NEAR
  668.         MOV    PAGE_PROC,OFFSET up_2    ;Set to move up 1 row
  669.         JMP    PAGE_UP_DN
  670. PGUP        ENDP
  671.  
  672. ;-----------------------------------------------------------------------
  673. ; This toggles the insert/overstrike mode.
  674. ;-----------------------------------------------------------------------
  675. INSERT        PROC    NEAR
  676.         NOT    INSERT_MODE        ;Toggle the switch
  677.         JMP    REDO_PROMPT        ;Redraw the insert status
  678. INSERT        ENDP
  679.  
  680. ;-----------------------------------------------------------------------
  681. ; This deletes the character at the cursor by shifting the remaining
  682. ; characters forward.
  683. ;-----------------------------------------------------------------------
  684. DEL_CHAR    PROC    NEAR
  685.         mov    save_flag,0        ;Set for ordinary delete
  686. del_ch2:
  687.         MOV    CX,LAST_CHAR
  688.         MOV    SI,CURSOR
  689.         MOV    DI,SI
  690.         CMP    SI,CX            ;Are we at end of file?
  691.         JAE    NO_DEL            ;If yes, then don't delete
  692.         mov    changed,1        ;Set file modified switch
  693.         LODSB
  694.         CALL    SAVE_CHAR        ;Save it for UNDO function
  695.         MOV    AH,[SI]            ;Look at the next character also
  696.         DEC    LAST_CHAR        ;Shorten the file by one
  697.         SUB    CX,SI
  698.         REP    MOVSB            ;Move file down one notch
  699.         CMP    AL,CR            ;Did we delete a CR?
  700.         JE    COMBINE
  701.         OR    DIRTY_BITS,4        ;Current line is dirty
  702. NO_DEL:
  703.         RET
  704. COMBINE:
  705.         CMP    AH,LF            ;Is the next character a LF?
  706.         JNE    NO_DEL_LF
  707.         cmp    save_flag,1        ;Is it bksp delete.
  708.         jne    del_ch4
  709.         mov    save_flag,2        ;Yes, set to save LF after CR
  710. del_ch4:
  711.         CALL    DEL_CH2            ;Now delete the line feed
  712. NO_DEL_LF:
  713.         CALL    DISPLAY_BOTTOM        ;Repaint bottom of the screen
  714.         MOV    DX,CUR_POSN
  715.         MOV    SAVE_COLUMN,DL        ;Save the cursor column
  716.         RET
  717. DEL_CHAR    ENDP
  718.  
  719. ;-----------------------------------------------------------------------
  720. ; This toggles the mark state and resets the paste buffer pointers.
  721. ;-----------------------------------------------------------------------
  722. MARK        PROC    NEAR
  723.         XOR    AX,AX
  724.         NOT    MARK_MODE        ;Toggle the mode flag
  725.         CMP    MARK_MODE,AL        ;Turning mode ON?
  726.         JNE    MARK_ON
  727.         MOV    DIRTY_BITS,1        ;Need to redraw the screen
  728.         MOV    MARK_START,0FFFFH
  729.         JMP    SHORT MARK_RET
  730. MARK_ON:
  731.         MOV    AX,CURSOR        ;Get the cursor offset
  732.         MOV    MARK_START,AX        ;Start of marked range
  733. MARK_RET:
  734.         MOV    MARK_END,  AX        ;End of marked range
  735.         MOV    MARK_HOME, AX        ;Center of marked range
  736.         RET
  737. MARK        ENDP
  738.  
  739. ;-----------------------------------------------------------------------
  740. ; This removes the marked text and places it in the paste buffer.
  741. ;-----------------------------------------------------------------------
  742. CUT        PROC    NEAR
  743.         CMP    MARK_MODE,0        ;Is the mark mode on?
  744.         JE    NO_MARK            ;If not, then do nothing
  745.         MOV    CX,MARK_END        ;Get end of mark region
  746.         MOV    SI,MARK_START        ;Get start of mark region
  747.         SUB    CX,SI            ;Number of bytes selected
  748.         MOV    PASTE_SIZE,CX
  749.         JCXZ    NO_MARK
  750.         mov    changed,1        ;Set file modified switch
  751.         mov    undo_length,0        ;Reset length of UNDO buffer.
  752.         XOR    DI,DI            ;Point to paste buffer
  753.  
  754.         PUSH    CX
  755.         PUSH    ES
  756.         MOV    ES,PASTE_SEG        ;Get the paste segment
  757.         REP    MOVSB            ;Put deleted text in buffer
  758.         POP    ES
  759.         POP    AX
  760.  
  761.         MOV    CX,LAST_CHAR
  762.         SUB    LAST_CHAR,AX        ;Shorten the file this much
  763.         MOV    DI,MARK_START
  764.         MOV    SI,MARK_END
  765.         SUB    CX,SI
  766.         JCXZ    NO_DELETE
  767.         REP    MOVSB            ;Shorten the file
  768. NO_DELETE:
  769.         MOV    DX,CUR_POSN
  770.         MOV    SI,MARK_START
  771.         CALL    LOCATE            ;Adjust the screen position
  772.         CALL    MARK            ;This turns off select
  773. NO_MARK:
  774.         RET
  775. CUT        ENDP
  776.  
  777. ;-----------------------------------------------------------------------
  778. ; This copies the paste buffer into the file at the cursor location.
  779. ;-----------------------------------------------------------------------
  780. PASTE        PROC    NEAR
  781.         MOV    AX,PASTE_SIZE        ;Number of characters in buffer
  782.         OR    AX,AX            ;Any there?
  783.         JZ    NO_PASTE        ;If not, nothing to paste
  784.         MOV    SI,CURSOR        ;Get cursor location
  785.         PUSH    AX
  786.         PUSH    SI
  787.         CALL    OPEN_SPACE        ;Make room for new characters
  788.         POP    DI
  789.         POP    CX
  790.         JC    NO_PASTE        ;If no room, just exit
  791.         mov    undo_length,0        ;Reset length of UNDO buffer.
  792.         XOR    SI,SI            ;Point to paste buffer
  793.         PUSH    DS
  794.         MOV    DS,PASTE_SEG        ;Segment of paste buffer
  795.         REP    MOVSB            ;Copy in the new characters
  796.         POP    DS
  797.         MOV    SI,DI
  798.         MOV    CURSOR,SI        ;Cursor moved to end of insert
  799.         MOV    DX,CUR_POSN        ;Get current cursor row
  800.         CALL    LOCATE            ;Adjust the screen position
  801.         MOV    DIRTY_BITS,1        ;Redraw the screen
  802. NO_PASTE:
  803.         RET
  804. PASTE        ENDP
  805.  
  806. ;-----------------------------------------------------------------------
  807. ; This prints the marked text.  If printer fails, it is canceled.
  808. ;-----------------------------------------------------------------------
  809. PRINT        PROC    NEAR
  810.         CMP    MARK_MODE,0        ;Is mark mode on?
  811.         JE    PRINT_RET        ;If not, nothing to print
  812.         MOV    CX,MARK_END        ;End of marked region
  813.         MOV    SI,MARK_START        ;Start of marked region
  814.         SUB    CX,SI            ;Number of bytes selected
  815.         JCXZ    PRINT_DONE        ;If nothing to print, return
  816.  
  817.         MOV    AH,2
  818.         XOR    DX,DX            ;Select printer 0
  819.         INT    17H            ;Get printer status
  820.         TEST    AH,10000000B        ;Is busy bit set?
  821.         JZ    PRINT_DONE
  822.         TEST    AH,00100000B        ;Is printer out of paper?
  823.         JNZ    PRINT_DONE
  824. PRINT_LOOP:
  825.         LODSB
  826.         XOR    AH,AH
  827.         INT    17H            ;Print the character
  828.         ROR    AH,1            ;Check time out bit
  829.         JC    PRINT_DONE        ;If set, quit printing
  830.         LOOP    PRINT_LOOP
  831.         MOV    AL,CR
  832.         XOR    AH,AH
  833.         INT    17H            ;Finish with a CR
  834. PRINT_DONE:
  835.         CALL    MARK            ;Turn off the mark state
  836. PRINT_RET:
  837.         RET
  838. PRINT        ENDP
  839.  
  840. ;-----------------------------------------------------------------------
  841. ; This command restores any characters which have recently been deleted.
  842. ;-----------------------------------------------------------------------
  843. UNDO        PROC    NEAR
  844.         XOR    AX,AX
  845.         XCHG    AX,UNDO_LENGTH        ;Get buffer length
  846.         MOV    SI,OFFSET UNDO_BUFFER
  847.         JMP    SHORT INSERT_STRING
  848. UNDO        ENDP
  849.  
  850. ;-----------------------------------------------------------------------
  851. ; This inserts AX characters from CS:SI into the file.
  852. ;-----------------------------------------------------------------------
  853. INSERT_STRING    PROC    NEAR
  854.         cmp    ax,0            ;Ignore if nothing to do
  855.         je    end_insert
  856.         PUSH    SI            ;Save string buffer
  857.         MOV    SI,CURSOR        ;Get cursor offset
  858.         PUSH    AX            ;Save length of string
  859.         PUSH    SI
  860.         CALL    OPEN_SPACE        ;Make space to insert string
  861.         POP    DI            ;Get back cursor position
  862.         POP    CX            ;Get back string length
  863.         POP    SI            ;Get back string buffer
  864.         JC    END_INSERT        ;If no space available, exit
  865.  
  866.         PUSH    DS
  867.         PUSH    CS
  868.         POP    DS
  869.         ASSUME    DS:CSEG
  870.         REP    MOVSB            ;Copy the characters in
  871.         MOV    SI,CURSOR        ;Get the new cursor offset
  872.         MOV    DX,CUR_POSN        ;Also get the current row
  873.         MOV    DIRTY_BITS,1        ;And redraw the screen
  874.         POP    DS
  875.         ASSUME    DS:NOTHING
  876.         CALL    LOCATE            ;Adjust the screen position
  877.         mov    cx,left_count
  878.         jcxz    end_insert
  879. right_more:                    ;Move cursor back to where
  880.         push    cx
  881.         call    right_2            ; it was before deleting
  882.         pop    cx
  883.         loop    right_more
  884. END_INSERT:
  885.         mov    left_count,0        ;Rest bksp del counter
  886.         RET
  887. INSERT_STRING    ENDP
  888.  
  889. ;-----------------------------------------------------------------------
  890. ; This adds a character to the undo buffer in the correct position.
  891. ;-----------------------------------------------------------------------
  892. SAVE_CHAR    PROC    NEAR
  893.         MOV    BX,UNDO_LENGTH        ;Get no. of chars. in buffer
  894.         OR    BH,BH            ;Is buffer filled?
  895.         JNZ    save_ch_end        ;Yes, exit
  896.         INC    UNDO_LENGTH        ;Add 1 to no. of chars.
  897.         or    bl,bl            ;If empty, save at beginning
  898.         jnz    save_1
  899.         mov    left_count,0        ; and zero out bksp del counter
  900.         jmp    short save_at_end
  901. save_1:
  902.         cmp    save_flag,0        ;Do we save at beginning or end?
  903.         jz    save_at_end        ;Go save at end
  904.         push    cx            ;Save at beginning - We must
  905.         mov    cx,bx            ; move existing contents up so
  906.         push    ax            ; can put new character in front
  907.         cmp    save_flag,2        ;Is it a LF character
  908.         jne    push_right        ; after a CR?
  909.         dec    cx            ;Yes, set to put it in second
  910.                         ; position in buffer which may
  911.         jcxz    save_it            ; be the end of the buffer.
  912. push_right:
  913.         dec    bx
  914.         mov    al,byte ptr cs:undo_buffer[bx]     ;Get byte
  915.         mov    byte ptr cs:undo_buffer[bx]+1,al ;Move it 1 to right
  916.         loop    push_right        ;Move all characters
  917. save_it:
  918.         pop    ax            ;Get original character
  919.         pop    cx            ;Restore cx
  920. save_at_end:
  921.         mov    byte ptr cs:undo_buffer[bx],al    ;Move it out
  922.         cmp    save_flag,1        ;Was it a bksp delete?
  923.         jne    save_ch_end
  924.         inc    left_count        ;Yes, bump counter
  925. save_ch_end:
  926.         RET
  927. SAVE_CHAR    ENDP
  928.  
  929. ;-----------------------------------------------------------------------
  930. ; This prompts for a verify keystroke then exits without saving the file.
  931. ;-----------------------------------------------------------------------
  932. ABORT        PROC    NEAR
  933.         ASSUME    DS:CSEG
  934.         PUSH    CS
  935.         POP    DS
  936.         cmp    changed,0        ;Was file modified?
  937.         je    finished        ;If not, skip warning
  938.         MOV    DH,ROWS            ;Last row on display
  939.         INC    DH            ;Bottom row of screen
  940.         XOR    DL,DL            ;First column
  941.         MOV    SI,OFFSET VERIFY_MSG
  942.         CALL    TTY_STRING        ;Display verify message
  943.  
  944.         XOR    AH,AH            ;Read the next key
  945.         INT    16H            ;BIOS read key routine
  946.         OR    AL,32            ;Convert to lower case
  947.         CMP    AL,"y"            ;Was answer Yes?
  948.         JE    FINISHED        ;If yes, then we're finished
  949.         CALL    REDO_PROMPT        ;If not, redraw the prompt
  950.         PUSH    ES
  951.         POP    DS            ;Set DS back to file segment
  952.         RET
  953. FINISHED:
  954.         MOV    DH,ROWS            ;Move to last row on screen
  955.         XOR    DL,DL            ;And column zero
  956.         CALL    SET_CURSOR
  957.         INC    DH
  958.         CALL    ERASE_EOL        ;Erase the last row
  959. EXIT_TO_DOS:
  960.         PUSH    CS
  961.         POP    DS            ;Point to code segment
  962.         MOV    DX,OFFSET COPYRIGHT
  963.         MOV    AH,9            ;Display string
  964.         INT    21H
  965.         MOV    AX,4C00H
  966.         INT    21H
  967. ABORT        ENDP
  968.  
  969. ;-----------------------------------------------------------------------
  970. ; This prompts for a filename then writes the file.  The original file
  971. ; is renamed to filename.BAK.  If an invalid filename is entered, the
  972. ; speaker is beeped.
  973. ;-----------------------------------------------------------------------
  974. EXIT        PROC    NEAR
  975.  
  976.         PUSH    DS
  977.         PUSH    ES
  978.         MOV    AX,CS
  979.         MOV    DS,AX
  980.         MOV    ES,AX
  981.         assume    es:cseg
  982. NEXT_LETTER:
  983.         MOV    DH,ROWS
  984.         INC    DH            ;Last row on the screen
  985.         XOR    DL,DL            ;First column
  986.         MOV    SI,OFFSET SAVE_MSG
  987.         PUSH    DX
  988.         CALL    TTY_STRING        ;Display a prompt
  989.         POP    DX
  990.         ADD    DL,9            ;Move right 9 spaces
  991.         MOV    SI,NAME_POINTER
  992.         CALL    TTY_STRING        ;Display the filename
  993.  
  994.         XOR    AH,AH            ;Read the next key
  995.         INT    16H
  996.         MOV    DI,NAME_END        ;This points to last letter
  997.         OR    AL,AL            ;Is it a real character?
  998.         JZ    NEXT_LETTER        ;Ignore special keys
  999.         CMP    AL,27            ;Is it escape?
  1000.         JNE    NOT_ESCAPE
  1001.  
  1002.         MOV    DIRTY_BITS,1        ;Redraw the screen
  1003.         POP    ES            ;Get back file segments
  1004.         POP    DS
  1005.         JMP    REDO_PROMPT        ;Redraw the prompt
  1006. NOT_ESCAPE:
  1007.         CMP    AL,13            ;Is it CR?
  1008.         JE    GOT_NAME
  1009.         CMP    AL,8            ;Is it a backspace?
  1010.         JNE    NORMAL_LETTER
  1011.         CMP    DI,NAME_POINTER        ;At first letter?
  1012.         JLE    NEXT_LETTER        ;If yes, dont erase it
  1013.         MOV    BYTE PTR [DI-1],0
  1014.         DEC    NAME_END
  1015.         JMP    NEXT_LETTER
  1016. NORMAL_LETTER:
  1017.         CMP    DI,81H + 65        ;Too many letters?
  1018.         JG    NEXT_LETTER        ;If yes, ignore them
  1019.         XOR    AH,AH
  1020.         STOSW                ;Store the new letter
  1021.         INC    NAME_END        ;Name is one character longer
  1022.         JMP    NEXT_LETTER        ;Read another keystroke
  1023. GOT_NAME:
  1024.         MOV    DX,NAME_POINTER        ;Point to the filename
  1025.         MOV    AX,4300H        ;Get the files attribute
  1026.         INT    21H
  1027.         JNC    NAME_OK            ;If no error, filename is OK
  1028.         CMP    AX,3            ;Was it path not found error?
  1029.         JE    BAD_NAME        ;If yes, filename was bad
  1030. NAME_OK:
  1031.         MOV    SI,OFFSET DOT_$$$    ;Point to the ".$$$"
  1032.         MOV    DI,OFFSET NAME_DOT_$$$
  1033.         CALL    CHG_EXTENSION        ;Add the new extension
  1034.  
  1035.         MOV    DX,OFFSET NAME_DOT_$$$    ;Point to the temp filename
  1036.         MOV    AH,3CH            ;Function to create file
  1037.         MOV    CX,0020H        ;Attribute for new file
  1038.         INT    21H            ;Try to create the file
  1039.         JNC    NAME_WAS_OK        ;Continue if name was OK
  1040. BAD_NAME:
  1041.         MOV    AX,0E07H        ;Write a bell character
  1042.         INT    10H            ;BIOS tty service
  1043.         JMP    NEXT_LETTER        ;Get another letter
  1044. WRITE_ERROR:
  1045.         MOV    AX,CS
  1046.         MOV    DS,AX
  1047.         MOV    AH,3EH            ;Close the file
  1048.         INT    21H
  1049.         JMP    BAD_NAME        ;Filename must be bad
  1050. NAME_WAS_OK:
  1051.         XOR    DX,DX            ;This is the file buffer
  1052.         MOV    CX,LAST_CHAR        ;Number of chars in file
  1053.         MOV    DI,CX
  1054.         MOV    BX,AX            ;This is the handle
  1055.         MOV    AH,40H            ;Write to the file
  1056.         POP    DS            ;Recover buffer segment
  1057.         CMP    CX,0FFFFH        ;Is buffer already full?
  1058.         JE    DONT_ADD_EOF        ;If yes, dont add EOF mark
  1059.         INC    CX            ;Plus one character for EOF mark
  1060.         MOV    BYTE PTR [DI],1AH    ;Add the EOF marker
  1061. DONT_ADD_EOF:
  1062.         INT    21H            ;Write the buffer contents
  1063.         PUSH    DS            ;Put DS back on the stack
  1064.         JC    WRITE_ERROR        ;Exit on a write error
  1065.         CMP    AX,CX            ;Was entire file written?
  1066.         JNE    WRITE_ERROR        ;If not, exit
  1067.  
  1068.         PUSH    CS
  1069.         POP    DS            ;Get the code segment
  1070.         MOV    AH,3EH
  1071.         INT    21H            ;Close the temp file
  1072.         MOV    SI,OFFSET DOT_BAK    ;Point to the ".BAK"
  1073.         MOV    DI,OFFSET NAME_DOT_BAK
  1074.         CALL    CHG_EXTENSION        ;Make the backup filename
  1075.  
  1076.         MOV    DX,OFFSET NAME_DOT_BAK    ;Point to the backup name
  1077.         MOV    AH,41H
  1078.         INT    21H            ;Delete existing backup file
  1079.         MOV    DI,OFFSET NAME_DOT_BAK
  1080.         MOV    DX,NAME_POINTER
  1081.         MOV    AH,56H
  1082.         INT    21H
  1083.  
  1084.         MOV    DI,NAME_POINTER        ;Point to new filename
  1085.         MOV    DX,OFFSET NAME_DOT_$$$    ;Point to temporary file
  1086.         MOV    AH,56H            ;Rename temp to new file
  1087.         INT    21H            ;DOS function to rename
  1088.         POP    AX            ;Restore the stack
  1089.         POP    AX
  1090.         JMP    FINISHED
  1091. EXIT        ENDP
  1092.  
  1093.  
  1094.  
  1095.         ;*************************;
  1096.         ;                         ;
  1097.         ;  S U B R O U T I N E S  ;
  1098.         ;                         ;
  1099.         ;*************************;
  1100.  
  1101.  
  1102. ;-----------------------------------------------------------------------
  1103. ; This subroutine displays a character by writing directly
  1104. ; to the screen buffer.  To avoid screen noise (snow) on the color
  1105. ; card, the horizontal retrace has to be monitored.
  1106. ;-----------------------------------------------------------------------
  1107. WRITE_INVERSE    PROC    NEAR
  1108.         ASSUME    DS:FILE_SEG, ES:FILE_SEG
  1109.         MOV    BH,INVERSE        ;Attribute for inverse video
  1110.         JMP    SHORT WRITE_SCREEN
  1111. WRITE_NORMAL:
  1112.         MOV    BH,NORMAL        ;Attribute for normal video
  1113. WRITE_SCREEN:
  1114.         MOV    BL,AL            ;Save the character
  1115.         PUSH    ES
  1116.         MOV    DX,STATUS_REG        ;Retrieve status register
  1117.         MOV    ES,VIDEO_SEG        ;Get segment of video buffer
  1118. HWAIT:
  1119.         IN    AL,DX            ;Get video status
  1120.         ROR    AL,1            ;Look at horizontal retrace
  1121.         JNC    HWAIT            ;Wait for retrace
  1122. WRITE_IT:
  1123.         MOV    AX,BX            ;Get the character/attribute
  1124.         STOSW                ;Write the character
  1125.         POP    ES
  1126.         RET
  1127. WRITE_INVERSE    ENDP
  1128.  
  1129. ;-----------------------------------------------------------------------
  1130. ; This moves the cursor to the row/column in DX.
  1131. ;-----------------------------------------------------------------------
  1132. SET_CURSOR    PROC    NEAR
  1133.         XOR    BH,BH            ;Were using page zero
  1134.         MOV    AH,2            ;BIOS set cursor function
  1135.         INT    10H
  1136.         RET
  1137. SET_CURSOR    ENDP
  1138.  
  1139. ;-----------------------------------------------------------------------
  1140. ; This computes the video buffer offset for the row/column in DX.
  1141. ;----------------------------------------------------------------------
  1142. POSITION    PROC    NEAR
  1143.         MOV    AX,COLUMNS        ;Take columns per row
  1144.         MUL    DH            ;Times row number
  1145.         XOR    DH,DH
  1146.         ADD    AX,DX            ;Add in the column number
  1147.         SHL    AX,1            ;Times 2 for offset
  1148.         MOV    DI,AX            ;Return result in DI
  1149.         RET
  1150. POSITION    ENDP
  1151.  
  1152. ;-----------------------------------------------------------------------
  1153. ; This erases from the location in DX to the right edge of the screen.
  1154. ;-----------------------------------------------------------------------
  1155. ERASE_EOL    PROC    NEAR
  1156.         CALL    POSITION        ;Find screen offset
  1157.         MOV    CX,COLUMNS        ;Get screen size
  1158.         SUB    CL,DL            ;Subtract current position
  1159.         JCXZ    NO_CLEAR
  1160. ERASE_LOOP:
  1161.         MOV    AL," "            ;Write blanks to erase
  1162.         CALL    WRITE_NORMAL        ;Display it
  1163.         LOOP    ERASE_LOOP
  1164. NO_CLEAR:    RET
  1165. ERASE_EOL    ENDP
  1166.  
  1167. ;-----------------------------------------------------------------------
  1168. ; This displays the function key prompt and insert mode state.
  1169. ;-----------------------------------------------------------------------
  1170. REDO_PROMPT    PROC    NEAR
  1171.         ASSUME    DS:NOTHING, ES:NOTHING
  1172.         PUSH    DS
  1173.         PUSH    CS
  1174.         POP    DS
  1175.         ASSUME    DS:CSEG
  1176.         MOV    DH,ROWS            ;Put prompt at last row
  1177.         INC    DH
  1178.         XOR    DL,DL            ;And column 0
  1179.         CALL    POSITION        ;Convert to screen offset
  1180.         MOV    SI,OFFSET PROMPT_STRING
  1181. KEY_LOOP:
  1182.         MOV    AL,"F"            ;Display an "F"
  1183.         CALL    WRITE_NORMAL
  1184.         LODSB
  1185.         OR    AL,AL            ;Last key in prompt?
  1186.         JZ    PROMPT_DONE
  1187.         CALL    WRITE_NORMAL
  1188.  
  1189.         CMP    BYTE PTR CS:[SI],"0"    ;Is it F10?
  1190.         JNE    TEXT_LOOP
  1191.         LODSB
  1192.         CALL    WRITE_NORMAL
  1193. TEXT_LOOP:
  1194.         LODSB
  1195.         OR    AL,AL            ;Last letter in word?
  1196.         JNZ    WRITE_CHAR
  1197.  
  1198.         MOV    AL," "            ;Display a space
  1199.         CALL    WRITE_NORMAL
  1200.         JMP    KEY_LOOP
  1201. WRITE_CHAR:
  1202.         CALL    WRITE_INVERSE        ;Display the letter
  1203.         JMP    TEXT_LOOP        ;Do the next letter
  1204. PROMPT_DONE:
  1205.         MOV    DH,ROWS
  1206.         INC    DH            ;Get to last row on screen
  1207.         MOV    DL,PROMPT_LENGTH + 9
  1208.         CALL    ERASE_EOL        ;Erase to the end of this row
  1209.         MOV    AL,"O"            ;Write an "O"
  1210.         CMP    INSERT_MODE,0        ;In insert mode?
  1211.         JE    OVERSTRIKE
  1212.         MOV    AL,"I"            ;Write an "I"
  1213. OVERSTRIKE:
  1214.         DEC    DI            ;Backup one character position
  1215.         DEC    DI
  1216.         CALL    WRITE_NORMAL
  1217.         POP    DS
  1218.         RET
  1219. REDO_PROMPT    ENDP
  1220.  
  1221. ;-----------------------------------------------------------------------
  1222. ; This displays the file buffer on the screen.
  1223. ;-----------------------------------------------------------------------
  1224. DISPLAY_SCREEN    PROC    NEAR
  1225.         ASSUME    DS:FILE_SEG, ES:FILE_SEG
  1226.         MOV    SI,TOP_OF_SCREEN    ;Point to first char on screen
  1227.         XOR    DH,DH            ;Start at first row
  1228.         JMP    SHORT NEXT_ROW
  1229. DISPLAY_BOTTOM:                    ;This redraws the bottom only
  1230.         CALL    FIND_START        ;Find first character on this row
  1231.         MOV    DX,CUR_POSN        ;Get current cursor row
  1232. NEXT_ROW:
  1233.         PUSH    DX
  1234.         CALL    DISPLAY_LINE        ;Display a line
  1235.         POP    DX
  1236.         INC    DH            ;Move to the next row
  1237.         CMP    DH,ROWS            ;At end of screen yet?
  1238.         JBE    NEXT_ROW        ;Do all the rows
  1239.         RET
  1240. DISPLAY_SCREEN    ENDP
  1241.  
  1242. ;-----------------------------------------------------------------------
  1243. ; This subroutine displays a single line to the screen.  DH holds the
  1244. ; row number, SI has the offset into the file buffer.  Tabs are expanded.
  1245. ; Adjustment is made for side shift.
  1246. ;-----------------------------------------------------------------------
  1247. DISPLAY_CURRENT    PROC    NEAR
  1248.         CALL    FIND_START
  1249.         MOV    DX,CUR_POSN
  1250. DISPLAY_LINE:
  1251.         XOR    DL,DL            ;Start at column zero
  1252.         MOV    MARGIN_COUNT,DL
  1253.         MOV    CX,DX            ;Use CL to count the columns
  1254.         CALL    POSITION        ;Compute offset into video
  1255. NEXT_CHAR:
  1256.         CMP    SI,LAST_CHAR        ;At end of file?
  1257.         JAE    LINE_DONE
  1258.         LODSB                ;Get next character
  1259.         CMP    AL,CR            ;Is it a carriage return?
  1260.         JE    FOUND_CR        ;Quit when a CR is found
  1261.         CMP    AL,TAB            ;Is this a Tab character
  1262.         JE    EXPAND_TAB        ;If yes, expand to spaces
  1263.         CALL    PUT_CHAR        ;Put character onto screen
  1264. TAB_DONE:
  1265.         CMP    CL,COLUMNSB        ;At right edge of screen?
  1266.         JB    NEXT_CHAR
  1267.         CMP    BYTE PTR [SI],CR    ;Is this the end of the line?
  1268.         JE    NOT_BEYOUND
  1269.         DEC    DI            ;Backup one character
  1270.         DEC    DI
  1271.         MOV    AL,4            ;Show a diamond
  1272.         CALL    WRITE_INVERSE        ;In inverse video
  1273. NOT_BEYOUND:
  1274.         JMP    FIND_NEXT        ;Find start of next line
  1275. FOUND_CR:
  1276.  
  1277. ;****disp
  1278.         mov    al,cr_disp        ;Delete these 2 instructions
  1279.         call    put_char        ; to suppress CR display.
  1280. ;****disp
  1281.  
  1282.         LODSB                ;Look at the next character
  1283.         CMP    AL,LF            ;Is it a line feed?
  1284.         JE    LINE_DONE
  1285.         DEC    SI
  1286. LINE_DONE:
  1287.         MOV    DX,CX
  1288.         JMP    ERASE_EOL        ;Erase the rest of the line
  1289. EXPAND_TAB:
  1290.         mov    al,tab_disp        ;Move out tab display symbol
  1291. tab_next:
  1292.         CALL    PUT_CHAR
  1293.         MOV    AL,MARGIN_COUNT
  1294.         ADD    AL,CL
  1295.         TEST    AL,00000111B        ;At even multiple of eight?
  1296.         jz    tab_done
  1297.         mov    al," "            ;Fill with spaces.
  1298.         jmp    short tab_next
  1299.  
  1300. DISPLAY_CURRENT    ENDP
  1301.  
  1302. ;-----------------------------------------------------------------------
  1303. ; This displays a single character to the screen.  If the character is
  1304. ; marked, it is shown in inverse video.  Characters outside the current
  1305. ; margin are not displayed.  Characters left of the margin are skipped.
  1306. ;-----------------------------------------------------------------------
  1307. PUT_CHAR    PROC    NEAR
  1308.         MOV    BL,MARGIN_COUNT        ;Get distance to left margin
  1309.         CMP    BL,LEFT_MARGIN        ;Are we inside left margin?
  1310.         JAE    IN_WINDOW        ;If yes, show the character
  1311.         INC    BL
  1312.         MOV    MARGIN_COUNT,BL
  1313.         RET
  1314. IN_WINDOW:
  1315.         CMP    SI,MARK_START        ;Is this character marked?
  1316.         JBE    NOT_MARKED
  1317.         CMP    SI,MARK_END
  1318.         JA    NOT_MARKED
  1319.         CALL    WRITE_INVERSE        ;Marked characters shown inverse
  1320.         JMP    SHORT NEXT_COL
  1321. NOT_MARKED:
  1322.         CALL    WRITE_NORMAL
  1323. NEXT_COL:
  1324.         INC    CL            ;Increment the column count
  1325.         RET
  1326. PUT_CHAR    ENDP
  1327.  
  1328. ;-----------------------------------------------------------------------
  1329. ; This subroutine inserts spaces into the file buffer.  On entry AX
  1330. ; contains the number of spaces to be inserted.  On return, CF=1 if
  1331. ; there was not enough space in the file buffer.
  1332. ;-----------------------------------------------------------------------
  1333. OPEN_SPACE    PROC    NEAR
  1334.         MOV    CX,LAST_CHAR        ;Last character in the file
  1335.         MOV    SI,CX
  1336.         MOV    DI,CX
  1337.         ADD    DI,AX            ;Offset for new end of file
  1338.         JC    NO_ROOM            ;If no more room, return error
  1339.         MOV    LAST_CHAR,DI        ;Save offset of end of file
  1340.         SUB    CX,CURSOR        ;Number of characters to shift
  1341.         DEC    DI
  1342.         DEC    SI
  1343.         STD                ;String moves goes forward
  1344.         REP    MOVSB            ;Shift the file upward
  1345.         CLD
  1346.         CLC
  1347. NO_ROOM:
  1348.         RET
  1349. OPEN_SPACE    ENDP
  1350.  
  1351. ;-----------------------------------------------------------------------
  1352. ; This subroutine adjusts the cursor position ahead to the saved cursor
  1353. ; column.  On entry DH has the cursor row.
  1354. ;-----------------------------------------------------------------------
  1355. SHIFT_RIGHT    PROC    NEAR
  1356.         MOV    CL,SAVE_COLUMN        ;Keep the saved cursor offset
  1357.         XOR    CH,CH
  1358.         MOV    BP,CX            ;Keep the saved cursor position
  1359.         ADD    CL,LEFT_MARGIN        ;Shift into visable window also
  1360.         ADC    CH,0
  1361.         XOR    DL,DL
  1362.         MOV    CUR_POSN,DX        ;Get cursor row/column
  1363.         JCXZ    NO_CHANGE
  1364. RIGHT_AGAIN:
  1365.         PUSH    CX
  1366.         CMP    BYTE PTR [SI],CR    ;At end of line?
  1367.         JE    DONT_MOVE        ;If at end, stop moving
  1368.         CALL    right_2            ;Move right one character
  1369. DONT_MOVE:
  1370.         POP    CX
  1371.  
  1372.         MOV    AL,SAVE_COLUMN
  1373.         XOR    AH,AH
  1374.         CMP    AX,CX            ;Is cursor still in margin?
  1375.         JL    IN_MARGIN        ;If yes, keep moving
  1376.  
  1377.         MOV    DX,CUR_POSN        ;Get cursor column again
  1378.         XOR    DH,DH
  1379.         CMP    DX,BP            ;At saved cursor position?
  1380.         JE    RIGHT_DONE        ;If yes, we're done
  1381.         JA    RIGHT_TOO_FAR        ;Did we go too far?
  1382. IN_MARGIN:
  1383.         LOOP    RIGHT_AGAIN
  1384. RIGHT_DONE:
  1385.         MOV    CX,BP
  1386.         MOV    SAVE_COLUMN,CL        ;Get back saved cursor position
  1387. NO_CHANGE:
  1388.         RET
  1389. RIGHT_TOO_FAR:
  1390.         CALL    left_2            ;Move left one place
  1391.         MOV    CX,BP
  1392.         MOV    SAVE_COLUMN,CL        ;Get back saved cursor position
  1393.         RET
  1394. SHIFT_RIGHT    ENDP
  1395.  
  1396. ;-----------------------------------------------------------------------
  1397. ; This subroutine skips past the CR and LF at SI.  SI returns new offset.
  1398. ;-----------------------------------------------------------------------
  1399. SKIP_CR_LF    PROC    NEAR
  1400.         CMP    SI,LAST_CHAR        ;At last char in the file?
  1401.         JAE    NO_SKIP            ;If yes, dont skip anything
  1402.         CMP    BYTE PTR [SI],CR    ;Is first character a CR?
  1403.         JNE    NO_SKIP
  1404.         INC    SI            ;Look at next character
  1405.         CMP    SI,LAST_CHAR        ;Is it at the end of file?
  1406.         JAE    NO_SKIP            ;If yes, dont skip anymore
  1407.         CMP    BYTE PTR [SI],LF    ;Is next character a line feed?
  1408.         JNE    NO_SKIP            ;Skip any line feeds also
  1409.         INC    SI
  1410. NO_SKIP:
  1411.         RET
  1412. SKIP_CR_LF    ENDP
  1413.  
  1414. ;-----------------------------------------------------------------------
  1415. ; This subroutine finds the beginning of the previous line.
  1416. ;-----------------------------------------------------------------------
  1417. FIND_PREVIOUS    PROC    NEAR
  1418.         PUSH    CURSOR            ;Save the cursor location
  1419.         CALL    FIND_CR            ;Find start of this line
  1420.         MOV    CURSOR,SI        ;Save the new cursor
  1421.         CALL    FIND_START        ;Find the start of this line
  1422.         POP    CURSOR            ;Get back starting cursor
  1423.         RET
  1424. FIND_PREVIOUS    ENDP
  1425.  
  1426. ;-----------------------------------------------------------------------
  1427. ; This searches for the previous carriage return.  Search starts at SI.
  1428. ;-----------------------------------------------------------------------
  1429. FIND_CR        PROC    NEAR
  1430.         PUSH    CX
  1431.         MOV    AL,CR            ;Look for a carriage return
  1432.         MOV    DI,SI
  1433.         MOV    CX,SI
  1434.         JCXZ    AT_BEGINNING
  1435.         DEC    DI
  1436.         STD                ;Search backwards
  1437.         REPNE    SCASB            ;Scan for the character
  1438.         CLD                ;Restore direction flag
  1439.         INC    DI
  1440.         MOV    SI,DI
  1441. AT_BEGINNING:
  1442.         POP    CX
  1443.         RET
  1444. FIND_CR        ENDP
  1445.  
  1446. ;-----------------------------------------------------------------------
  1447. ; This subroutine computes the location of the start of current line.
  1448. ; Returns SI pointing to the first character of the current line.
  1449. ;-----------------------------------------------------------------------
  1450. FIND_START    PROC    NEAR
  1451.         MOV    SI,CURSOR        ;Get the current cursor
  1452.         OR    SI,SI            ;At start of the file?
  1453.         JZ    AT_START        ;If yes, we're done
  1454.         CALL    FIND_CR            ;Find the
  1455.         CALL    SKIP_CR_LF
  1456. AT_START:
  1457.         RET
  1458. FIND_START    ENDP
  1459.  
  1460. ;-----------------------------------------------------------------------
  1461. ; This finds the offset of the start of the next line.  The search is
  1462. ; started at location ES:SI.  On return CF=1 of no CR was found.
  1463. ;-----------------------------------------------------------------------
  1464. FIND_NEXT    PROC    NEAR
  1465.         PUSH    CX
  1466.         CALL    FIND_EOL        ;Find the end of this line
  1467.         JC    AT_NEXT            ;If at end of file, return
  1468.         CALL    SKIP_CR_LF        ;Skip past CR and LF
  1469.         CLC                ;Indicate end of line found
  1470. AT_NEXT:
  1471.         POP    CX
  1472.         RET
  1473. FIND_NEXT    ENDP
  1474.  
  1475. ;-----------------------------------------------------------------------
  1476. ; This searches for the next carriage return in the file.  The search
  1477. ; starts at the offset in register SI.
  1478. ;-----------------------------------------------------------------------
  1479. FIND_EOL    PROC    NEAR
  1480.         MOV    AL,CR            ;Look for a carriage return
  1481.         MOV    CX,LAST_CHAR        ;Last letter in the file
  1482.         SUB    CX,SI            ;Count for the search
  1483.         MOV    DI,SI
  1484.         JCXZ    AT_END            ;If nothing to search, return
  1485.         REPNE    SCASB            ;Scan for the character
  1486.         MOV    SI,DI            ;Return the location of the CR
  1487.         JCXZ    AT_END            ;If not found, return
  1488.         DEC    SI
  1489.         CLC                ;Indicate the CR was found
  1490.         RET
  1491. AT_END:
  1492.         STC                ;Indicate CR was not found
  1493.         RET
  1494. FIND_EOL    ENDP
  1495.  
  1496. ;-----------------------------------------------------------------------
  1497. ; This subroutine positions the screen with the cursor at the row
  1498. ; selected in register DH.  On entry, SI holds the cursor offset.
  1499. ;-----------------------------------------------------------------------
  1500. LOCATE        PROC    NEAR
  1501.         MOV    CL,DH
  1502.         XOR    CH,CH
  1503.         MOV    CURSOR,SI
  1504.         XOR    DX,DX            ;Start at top of the screen
  1505.         OR    SI,SI            ;At start of buffer?
  1506.         JZ    LOCATE_FIRST
  1507.  
  1508.         CALL    FIND_START        ;Get start of this row
  1509.         XOR    DX,DX            ;Start at top of the screen
  1510.         OR    SI,SI            ;Is cursor at start of file?
  1511.         JZ    LOCATE_FIRST        ;If locating to top row
  1512.         JCXZ    LOCATE_FIRST        ; we're done
  1513. FIND_TOP:
  1514.         PUSH    SI
  1515.         PUSH    CX
  1516.         CALL    FIND_CR            ;Find previous row
  1517.         POP    CX
  1518.         POP    AX
  1519.         CMP    BYTE PTR [SI],CR
  1520.         JNE    LOCATE_FIRST
  1521.         CMP    SI,AX            ;Did it change?
  1522.         JE    LOCATE_DONE        ;If not, quit moving
  1523.         INC    DH            ;Cursor moves to next row
  1524.         LOOP    FIND_TOP
  1525.  
  1526. LOCATE_DONE:
  1527.         PUSH    CURSOR
  1528.         MOV    CURSOR,SI
  1529.         CALL    FIND_START        ;Find start of top of screen
  1530.         POP    CURSOR
  1531. LOCATE_FIRST:
  1532.         MOV    TOP_OF_SCREEN,SI
  1533.         MOV    CUR_POSN,DX
  1534.         CALL    CURSOR_COL
  1535.         MOV    SAVE_COLUMN,DL
  1536.         RET
  1537. LOCATE        ENDP
  1538.  
  1539. ;-----------------------------------------------------------------------
  1540. ; This subroutine computes the correct column for the cursor.  No
  1541. ; inputs.  On exit, CUR_POSN is set and DX has the row/column.
  1542. ;-----------------------------------------------------------------------
  1543. CURSOR_COL    PROC    NEAR
  1544.         MOV    SI,CURSOR        ;Get cursor offset
  1545.         CALL    FIND_START        ;Find start of this line
  1546.         MOV    CX,CURSOR
  1547.         SUB    CX,SI
  1548.         MOV    DX,CUR_POSN        ;Get current row
  1549.         XOR    DL,DL            ;Start at column zero
  1550.         MOV    MARGIN_COUNT,DL        ;Count past the left margin
  1551.         JCXZ    COL_DONE
  1552. CURSOR_LOOP:
  1553.         LODSB                ;Get the next character
  1554.         CMP    AL,CR            ;Is it the end of line?
  1555.         JE    COL_DONE        ;If end, we're done
  1556.         CMP    AL,TAB            ;Is it a tab?
  1557.         JNE    NOT_A_TAB
  1558.  
  1559.         MOV    BL,MARGIN_COUNT
  1560.         OR    BL,00000111B
  1561.         MOV    MARGIN_COUNT,BL
  1562.         CMP    BL,LEFT_MARGIN        ;Inside visible window yet?
  1563.         JB    NOT_A_TAB        ;If not, don't advance cursor
  1564.         OR    DL,00000111B        ;Move to multiple of eight
  1565. NOT_A_TAB:
  1566.         MOV    BL,MARGIN_COUNT
  1567.         INC    BL
  1568.         MOV    MARGIN_COUNT,BL
  1569.         CMP    BL,LEFT_MARGIN
  1570.         JBE    OUT_OF_WINDOW
  1571.         INC    DL            ;We're at next column now
  1572. OUT_OF_WINDOW:
  1573.         LOOP    CURSOR_LOOP
  1574. COL_DONE:
  1575.         CMP    DL,COLUMNSB        ;Past end of display?
  1576.         JB    COLUMN_OK        ;If not, we're OK?
  1577.         MOV    DL,COLUMNSB
  1578.         DEC    DL            ;Leave cursor at last column
  1579. COLUMN_OK:
  1580.         MOV    CUR_POSN,DX        ;Store the row/column
  1581.         RET
  1582. CURSOR_COL    ENDP
  1583.  
  1584. ;-----------------------------------------------------------------------
  1585. ; This displays the string at CS:SI at the location in DX.  The
  1586. ; remainder of the row is erased.  Cursor is put at the end of the line.
  1587. ;-----------------------------------------------------------------------
  1588. TTY_STRING    PROC    NEAR
  1589.         ASSUME    DS:CSEG
  1590.         PUSH    DX
  1591.         CALL    POSITION        ;Compute offset into video
  1592.         POP    DX
  1593. TTY_LOOP:
  1594.         LODSB
  1595.         OR    AL,AL            ;At end of string yet?
  1596.         JZ    TTY_DONE
  1597.         INC    DL
  1598.         PUSH    DX
  1599.         CALL    WRITE_INVERSE        ;Write in inverse video
  1600.         POP    DX
  1601.         JMP    TTY_LOOP
  1602. TTY_DONE:
  1603.         CALL    SET_CURSOR        ;Move cursor to end of string
  1604.         JMP    ERASE_EOL        ;Erase the rest of line
  1605. TTY_STRING    ENDP
  1606.  
  1607. ;-----------------------------------------------------------------------
  1608. ; This copies the input filename to CS:DI and changes the extension.
  1609. ;-----------------------------------------------------------------------
  1610. CHG_EXTENSION    PROC    NEAR
  1611.         assume    es:cseg
  1612.         PUSH    SI
  1613.         MOV    SI,NAME_POINTER
  1614. CHG_LOOP:
  1615.         LODSB
  1616.         CMP    AL,"."            ;Look for the extension
  1617.         JE    FOUND_DOT
  1618.         OR    AL,AL
  1619.         JZ    FOUND_DOT
  1620.         STOSB                ;Copy a character
  1621.         JMP    CHG_LOOP
  1622. FOUND_DOT:
  1623.         MOV    CX,5            ;Five chars in extension
  1624.         POP    SI
  1625.         REP    MOVSB            ;Move new extension in
  1626.         RET
  1627. CHG_EXTENSION    ENDP
  1628.  
  1629. ;-----------------------------------------------------------------------
  1630. ; This is the control break handler.  It ignores the break.
  1631. ;-----------------------------------------------------------------------
  1632. NEWINT23    PROC    FAR
  1633.         ASSUME    DS:NOTHING, ES:NOTHING
  1634.         MOV    CS:DIRTY_BITS,1
  1635.         CLC                ;Tell DOS to ignore break
  1636.         IRET
  1637. NEWINT23    ENDP
  1638.  
  1639. ;-----------------------------------------------------------------------
  1640. ; This is the severe error handler.  It homes the cursor before
  1641. ; processing the error.
  1642. ;-----------------------------------------------------------------------
  1643. NEWINT24    PROC    FAR
  1644.         PUSHF
  1645.         PUSH    AX
  1646.         PUSH    BX
  1647.         PUSH    DX
  1648.         MOV    CS:DIRTY_BITS,1
  1649.         XOR    DX,DX
  1650.         CALL    SET_CURSOR        ;Put cursor at home
  1651.         POP    DX
  1652.         POP    BX
  1653.         POP    AX
  1654.         POPF
  1655.         JMP    CS:OLDINT24
  1656. NEWINT24    ENDP
  1657.  
  1658. ;-----------------------------------------------------------------------
  1659.  
  1660. EVEN
  1661. NAME_DOT_$$$    EQU    $
  1662. NAME_DOT_BAK    EQU    $ + 80H
  1663. UNDO_BUFFER    EQU    $ + 100H
  1664. LINE_BUFFER    EQU    $ + 200H
  1665. NEW_STACK    EQU    $ + 500H
  1666. CSEG        ENDS
  1667.  
  1668. ;-----------------------------------------------------------------------
  1669.  
  1670. FILE_SEG    SEGMENT
  1671. FILE_SEG    ENDS
  1672.         END    START
  1673.